package com.geekhalo.lego.plugin.querymethod;

import com.geekhalo.lego.plugin.creator.JavaFileCreator;
import com.geekhalo.lego.plugin.support.util.Utils;
import com.intellij.ide.util.ClassFilter;
import com.intellij.ide.util.PackageChooserDialog;
import com.intellij.ide.util.TreeClassChooser;
import com.intellij.ide.util.TreeClassChooserFactory;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import static com.geekhalo.lego.plugin.support.util.Utils.hasImports;

public class CreateQueryMethodDialog extends DialogWrapper {
    private JPanel contentPane;
    private JTextField moduleName;
    private JTextField queryServicePkg;
    private JButton selectPkgBtn;
    private JTextField queryClassName;
    private JComboBox queryType;
    private JCheckBox isIntoPkg;
    private JTextField returnType;
    private JButton selectReturnTypeBtn;

    private final Project project;
    private final Module module;
    private final PsiClass queryService;

    public CreateQueryMethodDialog(Project project, Module module, PsiClass psiClass) {
        super(project);
        this.project = project;
        this.module = module;
        this.queryService = psiClass;
        setModal(true);
        initComponent();
        super.init();
    }

    private void initComponent() {
        this.moduleName.setText(this.module.getName());
        String pkg = Utils.getPkg(this.queryService.getQualifiedName());
        this.queryServicePkg.setText(pkg);
        String returnType = getReturnTypeFromQueryService(this.queryService);
        this.returnType.setText(returnType);

        this.queryType.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                onQueryTypeChanged(((JComboBox)e.getSource()).getSelectedItem());
            }
        });

        this.selectPkgBtn.addActionListener(e -> {
            PackageChooserDialog chooserDialog = new PackageChooserDialog("请选择包", project);
            if(chooserDialog.showAndGet()) {
                PsiPackage selectedPackage = chooserDialog.getSelectedPackage();
                if (selectedPackage != null) {
                    queryServicePkg.setText(selectedPackage.getQualifiedName());
                }
            }
        });

        this.selectReturnTypeBtn.addActionListener(e->{
            TreeClassChooserFactory factory = TreeClassChooserFactory.getInstance(project);
            // 设置过滤条件，只选择 public 类型的类
            ClassFilter classFilter = psiClass -> psiClass.getModifierList().hasExplicitModifier(PsiModifier.PUBLIC);
            // 弹出选择类的窗口
            TreeClassChooser chooser = factory.createWithInnerClassesScopeChooser(
                    "选择返回元素类型",
                    GlobalSearchScope.allScope(project),
                    classFilter,
                    null);
            chooser.showDialog();
            // 获取用户选择的类
            PsiClass selectedClass = chooser.getSelected();
            // 如果用户选择了类，则在控制台输出类名
            if (selectedClass != null) {
                this.returnType.setText(selectedClass.getQualifiedName());
            }
        });
    }

    private void onQueryTypeChanged(Object selectedItem) {
        String value = (String) selectedItem;
        if ("集合".equals(value)){
            this.queryClassName.setText("ListBy");
        }
        if ("单对象".equals(value)){
            this.queryClassName.setText("GetBy");
        }
        if ("分页".equals(value)){
            this.queryClassName.setText("PageBy");
        }
        if ("计数".equals(value)){
            this.queryClassName.setText("CountBy");
        }
    }

    private String getQueryMethod(){
        String value = (String) this.queryType.getSelectedItem();

        if ("集合".equals(value)){
            return "listOf";
        }
        if ("单对象".equals(value)){
            return "get";
        }
        if ("分页".equals(value)){
            return "pageOf";
        }
        if ("计数".equals(value)){
            return "countOf";
        }
        return "findBy";
    }

    private String getReturnTypeFromQueryService(PsiClass queryService) {
        PsiAnnotation annotation = queryService.getModifierList().findAnnotation("com.geekhalo.lego.core.query.QueryServiceDefinition");
        if (annotation == null){
            return "";
        }
        PsiAnnotationMemberValue value = annotation.findDeclaredAttributeValue("viewClass");
        if (value == null){
            value = annotation.findDeclaredAttributeValue("domainClass");
        }
        if (value == null){
            return "";
        }
        return Utils.getTypeFromClass(value.getText());
    }

    @Override
    protected void doOKAction(){
        createFiles();
        createMethod();
        super.doOKAction();
    }

    private void createMethod() {
        String methodName = getQueryMethod();
        String paramTypeFull = getQueryParamTypeFull();
        String returnItemTypeFull = getReturnItemTypeFull();
        String returnType = getReturnType();

        String methodStr = returnType + " " + methodName + "(@Valid " + Utils.getType(paramTypeFull) + " query);";

        PsiElementFactory elementFactory = JavaPsiFacade.getInstance(project).getElementFactory();
        final PsiMethod newMethod = elementFactory.createMethodFromText(methodStr, this.queryService);

        JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(project);
        WriteCommandAction.runWriteCommandAction(project, ()->{
            // 将新方法添加到目标类
            queryService.add(newMethod);

            // 将 import 语句添加到 PsiJavaFile 的 import 列表中
            PsiJavaFile javaFile = (PsiJavaFile) queryService.getContainingFile();
            PsiImportList importList = javaFile.getImportList();

            { // 导入 参数
                PsiClass psiClass = javaPsiFacade.findClass(paramTypeFull, GlobalSearchScope.allScope(this.project));
                if (psiClass!=null && !hasImports(importList, psiClass)) {
                    importList.add(elementFactory.createImportStatement(psiClass));
                }
            }
            if (returnItemTypeFull != null){ // 导入 返回值
                PsiClass psiClass = javaPsiFacade.findClass(returnItemTypeFull, GlobalSearchScope.allScope(this.project));
                if (psiClass != null && !hasImports(importList, psiClass)) {
                    importList.add(elementFactory.createImportStatement(psiClass));
                }
            }
        });
    }

    private String getReturnItemTypeFull() {
        String type = this.returnType.getText();
        if (type.contains(".")){
            return type;
        }else {
            return "";
        }
    }

    private String getReturnType() {
        String itemType =  Utils.getType(this.returnType.getText());

        String value = (String) this.queryType.getSelectedItem();

        if ("集合".equals(value)){
            return "List<" + itemType + ">";
        }
        if ("单对象".equals(value)){
            return itemType;
        }
        if ("分页".equals(value)){
            return "Page<" + itemType + ">";
        }
        if ("计数".equals(value)){
            return "Long";
        }
        return "Object";
    }

    private String getQueryParamTypeFull() {
        return getQueryObjectPkg() + "." + this.queryClassName.getText();
    }

    private void createFiles() {
        String queryObjectPkg = getQueryObjectPkg();
        QueryObjectTemplate.CreateQueryObjectContext context = new QueryObjectTemplate.CreateQueryObjectContext(queryObjectPkg, this.queryClassName.getText());
        String content = QueryObjectTemplate.create(context);

        JavaFileCreator.createJavaFileInPackage(this.project, this.module,
                queryObjectPkg, this.queryClassName.getText(),
                content);

    }

    private String getQueryObjectPkg() {
        if (this.isIntoPkg.isSelected()){
            return this.queryServicePkg.getText() + ".query";
        }
        return this.queryServicePkg.getText();
    }

    @Override
    public void doCancelAction(){
        super.doCancelAction();
    }


    @Override
    protected @Nullable JComponent createCenterPanel() {
        return this.contentPane;
    }
}
